package repository

import (
	"github.com/jinzhu/gorm"
	"mall-go/common"
	"mall-go/dto"
	"mall-go/model"
	"mall-go/util"
	"mall-go/vo"
	"strconv"
	"time"
)

const (
	LevelOne   = 1
	LevelTwo   = 2
	LevelThree = 3
)

type MallGoodsRepo struct {
	DB *gorm.DB
}

func NewMallGoodsRepo() MallGoodsRepo {
	db := common.GetDB()
	db.AutoMigrate(model.GoodsInfo{})
	return MallGoodsRepo{DB: db}
}

// GetGoodsCategoryById 根据主键id获取商品分类
func (receiver MallGoodsRepo) GetGoodsCategoryById(id int) model.GoodsCategory {
	var category model.GoodsCategory
	receiver.DB.First(&category, id)
	return category
}

// GetCategoriesForIndex 返回分类数据(首页调用)
func (receiver MallGoodsRepo) GetCategoriesForIndex() []vo.NewBeeMallIndexCategoryVO {
	var goodsCategoriesVO []vo.NewBeeMallIndexCategoryVO
	firstIds := []int{0}
	//获取一级分类的固定数量数据
	firstCategories := receiver.SelectByLevelAndParentIdsAndNumber(firstIds, 1, 10)
	if len(firstCategories) != 0 {
		//将一级分类的id拿出
		var firstLevelCategoryIds []int
		for _, category := range firstCategories {
			firstLevelCategoryIds = append(firstLevelCategoryIds, category.CategoryId)
		}
		//获取二级分类数据
		secondCategories := receiver.SelectByLevelAndParentIdsAndNumber(firstLevelCategoryIds, 2, 0)
		if len(secondCategories) != 0 {
			//将二级分类id拿出
			var secondLevelCategoryIds []int
			for _, category := range secondCategories {
				secondLevelCategoryIds = append(secondLevelCategoryIds, category.CategoryId)
			}
			//获取三级分类数据
			thirdCategories := receiver.SelectByLevelAndParentIdsAndNumber(secondLevelCategoryIds, 3, 0)
			if len(thirdCategories) != 0 {
				//根据parentId给三级分类数据进行分组
				thirdLevelCategoryMap := make(map[int][]model.GoodsCategory)
				for _, category := range thirdCategories {
					thirdLevelCategoryMap[category.ParentId] = append(thirdLevelCategoryMap[category.ParentId], category)
				}
				var secondLevelCategoryVOS []vo.SecondLevelCategoryVO
				//处理二级分类
				for _, category := range secondCategories {
					//先将查到的二级分类数据封装给vo
					secondLevelCategoryVO := vo.SecondLevelCategoryVO{
						CategoryId:    category.CategoryId,
						ParentId:      category.ParentId,
						CategoryLevel: category.CategoryLevel,
						CategoryName:  category.CategoryName,
					}
					//如果该二级分类下有数据则放入 secondLevelCategoryVOS 对象中
					if tempGoodsCategories, ok := thirdLevelCategoryMap[category.CategoryId]; ok {
						//根据二级分类的id取出thirdLevelCategoryMap分组中的三级分类list
						var thirdLevelCategoryVOS []vo.ThirdLevelCategoryVO
						//封装vo数据
						for _, goodsCategory := range tempGoodsCategories {
							thirdLevelCategoryVO := vo.ThirdLevelCategoryVO{
								CategoryId:    goodsCategory.CategoryId,
								CategoryLevel: goodsCategory.CategoryLevel,
								CategoryName:  goodsCategory.CategoryName,
							}
							thirdLevelCategoryVOS = append(thirdLevelCategoryVOS, thirdLevelCategoryVO)
						}
						secondLevelCategoryVO.ThirdLevelCategoryVO = thirdLevelCategoryVOS
						secondLevelCategoryVOS = append(secondLevelCategoryVOS, secondLevelCategoryVO)
					}
				}
				//处理一级分类
				if len(secondLevelCategoryVOS) != 0 {
					//根据 parentId 将 thirdLevelCategories 分组
					secondLevelCategoryVOMap := make(map[int][]vo.SecondLevelCategoryVO)
					for _, categoryVO := range secondLevelCategoryVOS {
						secondLevelCategoryVOMap[categoryVO.ParentId] = append(secondLevelCategoryVOMap[categoryVO.ParentId], categoryVO)
					}
					for _, category := range firstCategories {
						newBeeMallIndexCategoryVO := vo.NewBeeMallIndexCategoryVO{
							CategoryId:    category.CategoryId,
							CategoryLevel: category.CategoryLevel,
							CategoryName:  category.CategoryName,
						}
						//如果该一级分类下有数据则放入 newBeeMallIndexCategoryVOS 对象中
						if tempGoodsCategories, ok := secondLevelCategoryVOMap[category.CategoryId]; ok {
							newBeeMallIndexCategoryVO.SecondLevelCategoryVOS = tempGoodsCategories
							goodsCategoriesVO = append(goodsCategoriesVO, newBeeMallIndexCategoryVO)
						}
					}
				}
			}
		}
		return goodsCategoriesVO
	}
	return nil
}

// SelectByLevelAndParentIdsAndNumber 根据level、parentId、Number查询
func (receiver MallGoodsRepo) SelectByLevelAndParentIdsAndNumber(parentIds []int, categoryLevel int, number int) []model.GoodsCategory {
	var goodsCategories []model.GoodsCategory
	//将parentIds转换成逗号分隔字符串
	strParentids := util.Convert(parentIds)
	tx := receiver.DB.Where("parent_id in ("+strParentids+") and category_level = ? and is_deleted = 0", categoryLevel).Order("category_rank desc")
	if number > 0 {
		tx = tx.Limit(number)
	}
	tx.Find(&goodsCategories)
	return goodsCategories
}

// GetNewBeeMallGoodsById 根据商品id找到对应的商品详情
func (receiver MallGoodsRepo) GetNewBeeMallGoodsById(goodsId int) model.GoodsInfo {
	var goodsInfo model.GoodsInfo
	receiver.DB.Debug().Where("goods_id = ?", goodsId).Find(&goodsInfo)
	return goodsInfo
}

//根据商品id集合找到所有商品
func (receiver MallGoodsRepo) findGoodsByIds(goodsId []uint) []model.GoodsInfo {
	var goodses []model.GoodsInfo
	//拼接成字符串
	strGoodsIds := util.Convert(goodsId)
	receiver.DB.Raw("select * from tb_newbee_mall_goods_info where goods_id in (" + strGoodsIds + ")").Find(&goodses)
	//解决文字过长问题
	for i, goods := range goodses {
		goodsName := goods.GoodsName
		goodsIntro := goods.GoodsIntro
		if len(goodsName) > 30 {
			goodsName = goodsName[:30] + "..."
			goodses[i].GoodsName = goodsName
		}
		if len(goodsIntro) > 22 {
			goodsIntro = goodsIntro[:22] + "..."
			goodses[i].GoodsIntro = goodsIntro
		}
	}
	return goodses
}

// SearchNewBeeMallGoods 商品搜索
func (receiver MallGoodsRepo) SearchNewBeeMallGoods(goodsPageDTO dto.GoodsPageDTO) vo.GoodsPageResult {
	goodsList := receiver.findNewBeeMallGoodsListBySearch(goodsPageDTO)
	total := receiver.getTotalNewBeeMallGoodsBySearch(goodsPageDTO)
	if len(goodsList) != 0 {
		//todo 这里偷个懒就不转成vo数据了
		for i, goodsInfo := range goodsList {
			//处理字符串过长问题
			goodsName := goodsInfo.GoodsName
			goodsIntro := goodsInfo.GoodsIntro
			if len(goodsName) > 28 {
				goodsName = goodsName[:28] + "..."
				goodsList[i].GoodsName = goodsName
			}
			if len(goodsIntro) > 30 {
				goodsIntro = goodsIntro[:30] + "..."
				goodsList[i].GoodsIntro = goodsIntro
			}
		}
	}
	return vo.GoodsPageResult{
		PageResult: vo.PageResult{
			TotalCount: total,
			PageSize:   goodsPageDTO.Limit,
			TotalPage:  total / goodsPageDTO.Limit,
			CurrPage:   goodsPageDTO.Page,
		},
		List: goodsList,
	}
}

//搜索商品数据库查询
func (receiver MallGoodsRepo) findNewBeeMallGoodsListBySearch(pageDTO dto.GoodsPageDTO) []model.GoodsInfo {
	var goodsList []model.GoodsInfo
	tx := receiver.DB.Debug()
	if len(pageDTO.Keyword) != 0 && pageDTO.Keyword != "" {
		tx = tx.Where("goods_name like ?", "%"+pageDTO.Keyword+"%").Or("goods_intro like ?", "%"+pageDTO.Keyword+"%")
	}
	if pageDTO.GoodsCategoryId != 0 {
		tx = tx.Where("goods_category_id = ?", pageDTO.GoodsCategoryId)
	}
	if pageDTO.GoodsSellStatus != 0 {
		tx = tx.Where("goods_sell_status = ?", pageDTO.GoodsSellStatus)
	}
	//按照哪种排序方式：发布时间、售价从小到大、（默认）按照库存量大到小
	if pageDTO.OrderBy == "new" {
		tx = tx.Order("goods_id desc")
	} else if pageDTO.OrderBy == "price" {
		tx = tx.Order("selling_price asc")
	} else {
		//默认
		tx = tx.Order("stock_num desc")
	}

	if pageDTO.Start != 0 && pageDTO.Limit != 0 {
		tx = tx.Limit(pageDTO.Limit).Offset(pageDTO.Start)
	}
	tx.Find(&goodsList)
	return goodsList
}

//用于商城商品搜索列表
func (receiver MallGoodsRepo) getTotalNewBeeMallGoodsBySearch(pageDTO dto.GoodsPageDTO) int {
	var total int
	tx := receiver.DB.Debug().Model(&model.GoodsInfo{})
	if len(pageDTO.Keyword) != 0 && pageDTO.Keyword != "" {
		tx = tx.Where("goods_name like ?", "%"+pageDTO.Keyword+"%").Or("goods_intro like ?", "%"+pageDTO.Keyword+"%")
	}
	if pageDTO.GoodsCategoryId != 0 {
		tx = tx.Where("goods_category_id = ?", pageDTO.GoodsCategoryId)
	}
	if pageDTO.GoodsSellStatus != 0 {
		tx = tx.Where("goods_sell_status = ?", pageDTO.GoodsSellStatus)
	}
	tx.Count(&total)
	return total
}

func (receiver MallGoodsRepo) GetCategoriesPage(pageDTO dto.CategoryPageDTO) vo.CategoryPageResult {
	//查询商品分类分页数据集合
	var list []model.GoodsCategory
	receiver.DB.Debug().Where("category_level = ?", pageDTO.CategoryLevel).
		Where("parent_id = ?", pageDTO.ParentId).
		Where("is_deleted = ?", 0).
		Order("category_rank desc").Offset(pageDTO.Start).Limit(pageDTO.Limit).Find(&list)

	//查询总记录数
	var total int
	receiver.DB.Debug().Model(&model.GoodsCategory{}).Where("category_level = ?", pageDTO.CategoryLevel).Where("parent_id = ?", pageDTO.ParentId).
		Where("is_deleted = ?", 0).Count(&total)
	page := vo.CategoryPageResult{
		PageResult: vo.PageResult{
			TotalCount: total,
			PageSize:   pageDTO.Limit,
			TotalPage:  total / pageDTO.Limit,
			CurrPage:   pageDTO.Page,
		},
		List: list,
	}
	return page
}

func (receiver MallGoodsRepo) SaveCategory(param dto.GoodsCategoryAddParam, id uint) bool {
	//根据等级和名字查询
	var temp model.GoodsCategory
	receiver.DB.Where("category_name = ?", param.CategoryName).Where("category_level = ?", param.CategoryLevel).
		Where("is_deleted = ?", 0).First(&temp)
	if temp.CategoryId != 0 {
		panic("重复添加")
	}
	//封装数据添加至数据库
	rank, _ := strconv.Atoi(param.CategoryRank)
	category := model.GoodsCategory{
		CategoryLevel: param.CategoryLevel,
		ParentId:      *param.ParentId,
		CategoryName:  param.CategoryName,
		CategoryRank:  uint(rank),
		CreateUser:    int(id),
		UpdateUser:    int(id),
	}
	//添加操作
	if err := receiver.DB.Model(category).Create(&category).Error; err != nil {
		panic("添加失败")
	}
	return true
}

func (receiver MallGoodsRepo) UpdateGoodsCategory(param dto.GoodsCategoryEditParam, id uint) bool {
	var temp model.GoodsCategory
	receiver.DB.First(&temp, param.CategoryId)
	if temp.CategoryId == 0 {
		panic("数据不存在")
	}
	var temp2 model.GoodsCategory
	receiver.DB.Where("category_name = ?", param.CategoryName).Where("category_level = ?", param.CategoryLevel).
		Where("is_deleted = ?", 0).First(&temp2)
	if temp2.CategoryId != 0 && temp2.CategoryId != param.CategoryId {
		panic("已存在同级同名的分类")
	}
	//商品分类更新数据封装
	category := model.GoodsCategory{
		CategoryId:    param.CategoryId,
		CategoryLevel: param.CategoryLevel,
		ParentId:      *param.ParentId,
		CategoryName:  param.CategoryName,
		CategoryRank:  uint(param.CategoryRank),
		UpdateTime:    model.Time(time.Now()),
		UpdateUser:    int(id),
	}
	if err := receiver.DB.Model(&category).Update(category).Where("category_id = ?", category.CategoryId).Error; err != nil {
		panic("更新失败")
	}
	return true
}

func (receiver MallGoodsRepo) BatchDelete(param dto.BatchIdParam) {
	if err := receiver.DB.Debug().Model(&model.GoodsCategory{}).
		Where("category_id in ("+util.Convert(param.UserIds)+")").Update("is_deleted", 1).Error; err != nil {
		panic("删除失败")
	}
}

// GetNewBeeMallGoodsPage 用于后台商品列表展示
func (receiver MallGoodsRepo) GetNewBeeMallGoodsPage(pageDTO dto.GoodsPageDTO) []model.GoodsInfo {
	var goodsList []model.GoodsInfo
	tx := receiver.DB.Debug()
	if len(pageDTO.Keyword) != 0 && pageDTO.Keyword != "" {
		tx = tx.Where("goods_name like ?", "%"+pageDTO.Keyword+"%").Or("goods_intro like ?", "%"+pageDTO.Keyword+"%")
	}
	if pageDTO.GoodsSellStatus != 0 {
		tx = tx.Where("goods_sell_status = ?", pageDTO.GoodsSellStatus)
	}
	tx.Order("goods_id desc").Limit(pageDTO.Limit).Offset(pageDTO.Start).Find(&goodsList)
	return goodsList
}

// GetTotalNewBeeMallGoods 用于后台展示商品列表总记录数
func (receiver MallGoodsRepo) GetTotalNewBeeMallGoods(pageDTO dto.GoodsPageDTO) int {
	var total int
	tx := receiver.DB.Debug().Model(&model.GoodsInfo{})
	if len(pageDTO.Keyword) != 0 && pageDTO.Keyword != "" {
		tx = tx.Where("goods_name like ?", "%"+pageDTO.Keyword+"%").Or("goods_intro like ?", "%"+pageDTO.Keyword+"%")
	}
	if pageDTO.GoodsSellStatus != 0 {
		tx = tx.Where("goods_sell_status = ?", pageDTO.GoodsSellStatus)
	}
	tx.Count(&total)
	return total
}

func (receiver MallGoodsRepo) SaveGoods(param dto.GoodsAddParam, id uint) bool {
	//根据主键查询商品分类
	var temp model.GoodsCategory
	receiver.DB.First(&temp, *param.GoodsCategoryId)
	//如果分类不存在或者不属于三级分类返回异常
	if temp.CategoryId == 0 || temp.CategoryLevel != LevelThree {
		panic("参数异常")
	}
	//根据商品分类id和名称查询商品数据
	var tempGoods model.GoodsInfo
	receiver.DB.Where("good_name = ?", param.GoodsName).
		Where("goods_category_id = ?", param.GoodsCategoryId).First(&tempGoods)
	if tempGoods.GoodsId != 0 {
		panic("请勿重复添加")
	}
	//封装商品数据entity
	//前端请求参数有问题，golang不支持int和string之间的强转
	price, _ := strconv.Atoi(param.SellingPrice)
	status, _ := strconv.Atoi(param.GoodsSellStatus)
	stockNum, _ := strconv.Atoi(param.StockNum)
	originalPrice, _ := strconv.Atoi(param.OriginalPrice)
	goods := model.GoodsInfo{
		GoodsName:          param.GoodsName,
		GoodsIntro:         param.GoodsIntro,
		GoodsCategoryId:    *param.GoodsCategoryId,
		GoodsCoverImg:      param.GoodsCoverImg,
		GoodsDetailContent: param.GoodsDetailContent,
		OriginalPrice:      originalPrice,
		SellingPrice:       price,
		StockNum:           stockNum,
		Tag:                param.Tag,
		GoodsSellStatus:    status,
		CreateUser:         id,
		UpdateUser:         id,
	}
	if err := receiver.DB.Create(&goods).Error; err != nil {
		panic("添加失败")
	}
	return true
}

func (receiver MallGoodsRepo) UpdateNewBeeMallGoods(param dto.GoodsEditParam, id uint) bool {
	//根据主键查询商品分类
	var temp model.GoodsCategory
	receiver.DB.First(&temp, *param.GoodsCategoryId)
	// 分类不存在或者不是三级分类，则该参数字段异常
	if temp.CategoryId == 0 || temp.CategoryLevel != LevelThree {
		panic("参数异常")
	}
	//根据主键查询商品
	var temp2 model.GoodsInfo
	receiver.DB.First(&temp2, param.GoodsId)
	if temp2.GoodsId == 0 {
		panic("数据不存在")
	}
	//根据商品分类id和名称查询商品数据
	var tempGoods model.GoodsInfo
	receiver.DB.Where("good_name = ?", param.GoodsName).
		Where("goods_category_id = ?", param.GoodsCategoryId).First(&tempGoods)
	//这里请求参数给的有问题，golang不支持强转
	goodsId, _ := strconv.Atoi(param.GoodsId)
	if tempGoods.GoodsId != 0 && tempGoods.GoodsId != goodsId {
		panic("不能修改")
	}
	//修改商品数据
	//封装商品数据
	status, _ := strconv.Atoi(param.GoodsSellStatus)
	goods := model.GoodsInfo{
		GoodsId:            goodsId,
		GoodsName:          param.GoodsName,
		GoodsIntro:         param.GoodsIntro,
		GoodsCategoryId:    *param.GoodsCategoryId,
		GoodsCoverImg:      param.GoodsCoverImg,
		GoodsCarousel:      param.GoodsName,
		GoodsDetailContent: param.GoodsDetailContent,
		OriginalPrice:      param.OriginalPrice,
		SellingPrice:       param.SellingPrice,
		StockNum:           param.StockNum,
		Tag:                param.Tag,
		GoodsSellStatus:    status,
		UpdateTime:         model.Time(time.Now()),
		UpdateUser:         id,
	}
	if err := receiver.DB.Model(&model.GoodsInfo{}).Update(goods).Where("goods_id = ?", param.GoodsId).Error; err != nil {
		panic("修改失败")
	}
	return true
}

func (receiver MallGoodsRepo) BatchUpdateSellStatus(ids []int, status int, id uint) bool {
	//当更新字段有零值的时候可以构造一个map进行传参，要记住传递的是map的值而不是地址，否则零值依旧不能传入
	values := map[string]interface{}{
		"goods_sell_status": status,
		"update_user":       id,
		"update_time":       time.Now(),
	}
	if err := receiver.DB.Debug().Table("tb_newbee_mall_goods_info").Where("goods_id in (?)", ids).
		Updates(values).Error; err != nil {
		panic("修改失败")
	}
	return true
}
